package com.diy.sigmund.diycommon.testsome;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;
import java.util.NavigableMap;
import java.util.TreeMap;
import java.util.stream.Collectors;

/**
 * @ClassName: GroupManyColSum https://www.cnblogs.com/stjwy/p/14074175.html
 * @Description: 单字段分组，多字段求和
 * @Date: 2021/3/13
 * @Author: cakin
 */
public class StreamGroupManyColSum {

    /**
     * @className: GroupManyColSum
     * @description: 单字段分组，多字段求和
     * @date: 2021/3/14
     * @author: cakin
     */
    public static void main(String[] args) {
        List<Student> studentList = new ArrayList();
        studentList.add(new Student("321", 65L, 54, new BigDecimal(387)));
        studentList.add(new Student("123", 78L, 99, new BigDecimal(340)));
        studentList.add(new Student("123", 45L, 76, new BigDecimal(367)));
        studentList.add(new Student("223", 45L, 76, new BigDecimal(367)));

        // 仅分组 TreeMap 升序
//        final TreeMap<String, List<Student>> collect = studentList.stream()
//                .collect(Collectors.groupingBy(Student::getCode, TreeMap::new, Collectors.toList()));

        // 仅分组 LinkedHashMap 顺序
//        final LinkedHashMap<String, List<Student>> collect = studentList.stream()
//                .collect(Collectors.groupingBy(Student::getCode, LinkedHashMap::new, Collectors.toList()));

        // 仅分组 new TreeMap().descendingMap() 降序
        final NavigableMap collect = studentList.stream()
                .collect(Collectors
                        .groupingBy(Student::getCode, () -> new TreeMap().descendingMap(), Collectors.toList()));
        System.out.println(collect);

        // 以 code 为分组字段，对 achievement score money 分别求和
//        List<Student> list = studentList
//                .stream()
//                // groupingBy的第1个参数为分组字段，第2个参数为求和公式
//                .collect(Collectors.groupingBy(Student::getCode, TreeMap::new, Collectors.reducing((sum, s) ->
//                        getStudent(sum, s))))
//                .entrySet()
//                .stream()
//                .map(c -> c.getValue().get())
//                .collect(Collectors.toList());
//        for (Student student : list) {
//            System.out.println(student);
//        }
//        Supplier supplier = new Supplier() {
//            @Override
//            public Object get() {
//                return new TreeMap<>();
//            }
//        };
//        Collector collector = Collectors.toList();
//        studentList
//                .stream()
//                // groupingBy的第1个参数为分组字段，第2个参数为求和公式
//                .collect(Collectors.groupingBy(Student::getCode, supplier, collector));
    }

    /**
     * sum对象是分组后的第一个元素，s是第二个，sum和s操作后new的新对象赋值给sum再次参与计算
     *
     * @param sum sum
     * @param s   s
     * @return Student
     */
    private static Student getStudent(Student sum, Student s) {
        final Student student = new Student(s.getCode(), sum.getAchievement() + s.getAchievement(),
                sum.getScore() + s.getScore(), sum.getMoney().add(s.getMoney()));
        return student;
    }
}

/**
 * @className: GroupManyColSum
 * @description: 学生类
 * @date: 2021/3/14
 * @author: cakin
 */
class Student {

    /**
     * 学号
     */
    private String code;
    /**
     * 成绩
     */
    private Long achievement;
    /**
     * 学分
     */
    private Integer score;
    /**
     * 学费
     */
    private BigDecimal money;

    public Student() {
    }

    public Student(String code, Long achievement, Integer score, BigDecimal money) {
        this.code = code;
        this.achievement = achievement;
        this.score = score;
        this.money = money;
    }

    public String getCode() {
        return code;
    }

    public void setCode(String code) {
        this.code = code;
    }

    public Long getAchievement() {
        return achievement;
    }

    public void setAchievement(Long achievement) {
        this.achievement = achievement;
    }

    public Integer getScore() {
        return score;
    }

    public void setScore(Integer score) {
        this.score = score;
    }

    public BigDecimal getMoney() {
        return money;
    }

    public void setMoney(BigDecimal money) {
        this.money = money;
    }

    @Override
    public String toString() {
        return "Student{" +
                "code='" + code + '\'' +
                ", achievement=" + achievement +
                ", score=" + score +
                ", money=" + money +
                '}';
    }

}